/*******************************************************************************
 * 定时任务
 *
 *******************************************************************************/
#include "bsp.h"
#include "framework.h"
#include "lib_surport.h"

#define APP_TIM TIM7
#define APP_TIM_IRQn TIM7_IRQn
#define app_timer_isr APP_TIM7_IRQHandler

#define APP_TIM_PERIOD 1000

/******************************************************************************
 *	                            function
 *******************************************************************************/
uint32_t app_tick_init(uint32_t TickPriority);
void app_tick_suspend(void);
void app_tick_resume(void);
uint32_t app_tick_get(void);
uint32_t app_tick_us_get(void);
static uu08 app_tick_div;
void app_tick_isr(void);

/******************************************************************************
 *	                            var
 *******************************************************************************/
uint32_t isr_exe_clk_max = 0;
uint32_t hal_tick_cnt = 0;
static vtask_vector_type task_vect;
static void (*task_list[16])(void);
static char inited = 0;

/*******************************************************************************
 * @brief  app_tick_init
 * \param[in] none
 * \retval: none
 *******************************************************************************/
uint32_t app_tick_init(uint32_t TickPriority)
{
	uint32_t clocks;
	intx_alloc();

	// 使能定时器时钟
	intx_disable();
	__HAL_RCC_TIM7_CLK_ENABLE();
	__HAL_RCC_TIM7_FORCE_RESET();
	__HAL_RCC_TIM7_RELEASE_RESET();
	intx_enable();

	// 获取时钟值
	clocks = HAL_RCC_GetPCLK1Freq();

	// 配置
	APP_TIM->CR1 = 0;
	APP_TIM->CR2 = 0;

	APP_TIM->DIER = 0;
	APP_TIM->SR = 0;

	/*0.5ms interrupt*/
	APP_TIM->PSC = (clocks / 1000000) - 1;
	APP_TIM->ARR = APP_TIM_PERIOD - 1;

	// nvic
	nvic_irq_set(APP_TIM_IRQn, 0x03, 1);

	APP_TIM->CR1 |= TIM_CR1_URS;
	APP_TIM->CR1 |= TIM_CR1_CEN;

	vtask_list_init(&task_vect, task_list, sizeof(task_list) / 4, 0);

	APP_TIM->DIER = TIM_CR1_CEN;

	inited = 1;
	hal_tick_cnt = 0;

	return 0;
}

/*******************************************************************************
 * @brief  app_tick_suspend
 * \param[in] none
 * \retval: none
 *******************************************************************************/
void app_tick_suspend(void)
{
	APP_TIM->DIER = 0;
}

/*******************************************************************************
 * @brief  app_tick_resume
 * \param[in] none
 * \retval: none
 *******************************************************************************/
void app_tick_resume(void)
{
	APP_TIM->DIER = 1;
}

/*******************************************************************************
 * @brief  app_tick_get
 * \param[in] none
 * \retval: none
 *******************************************************************************/
uint32_t app_tick_get(void)
{
	return hal_tick_cnt;
}

/*******************************************************************************
 * @brief  app_tick_us_get
 * \param[in] none
 * \retval: none
 *******************************************************************************/
uint32_t app_tick_us_get(void)
{
	uint32_t time_us;

	intx_alloc();

	intx_disable();

	time_us = hal_tick_cnt * APP_TIM_PERIOD;

	time_us += APP_TIM->CNT & 0x0000FFFF;

	intx_enable();

	return time_us;
}

/*******************************************************************************
 * @brief  app_tick_isr
 * \param[in] none
 * \retval: none
 *******************************************************************************/
void app_timer_isr(void)
{
	uint32_t tick;
	
	APP_TIM->SR = 0;
	tick = bsp_cpu_clks_get();
	app_tick_div ++;
	
	// 定时任务执行
	if(inited && (app_tick_div & 1))
	{
		hal_tick_cnt++;
		lib_tick16_cnt ++;
		lib_tick32_cnt ++;
		vtask_list_run_once(&task_vect);
	}
	
	// 执行时间计算
	tick = bsp_cpu_clks_get() - tick;
	if(tick > isr_exe_clk_max)
		isr_exe_clk_max = tick;
}

/*******************************************************************************
 * @brief  app timer task add
 * \param[in] none
 * \retval: none
 *******************************************************************************/
void app_timer_task_add(void (*task)(void))
{
	intx_alloc();

	intx_disable();

	vtask_list_add(&task_vect, task);

	intx_enable();
}

/*******************************************************************************
 * @brief  app timer task del
 * \param[in] none
 * \retval: none
 *******************************************************************************/
void app_timer_task_del(void (*task)(void))
{
	intx_alloc();

	intx_disable();

	vtask_list_del(&task_vect, task);

	intx_enable();
}
